package com.agileai.bpm.domain.define;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.xmlbeans.XmlException;

import com.agileai.bpm.common.ProcessDefineUtil;
import com.agileai.bpm.interceptor.BaseInterceptor;
import com.agileai.bpm.interceptor.InterceptorFactory;
import com.agileai.bpm.model.ActivitiesDocument.Activities;
import com.agileai.bpm.model.AuditActivityType;
import com.agileai.bpm.model.DataFieldsDocument.DataFields;
import com.agileai.bpm.model.EndActivityType;
import com.agileai.bpm.model.ForkActivityType;
import com.agileai.bpm.model.InInterceptorsDocument.InInterceptors;
import com.agileai.bpm.model.InterceptorModelDocument.InterceptorModel;
import com.agileai.bpm.model.InvokeActivityType;
import com.agileai.bpm.model.JoinActivityType;
import com.agileai.bpm.model.ManualActivityType;
import com.agileai.bpm.model.OutInterceptorsDocument.OutInterceptors;
import com.agileai.bpm.model.ProcessDefineDocument;
import com.agileai.bpm.model.ProcessDefineDocument.ProcessDefine;
import com.agileai.bpm.model.StartActivityType;
import com.agileai.bpm.model.TransitionType;
import com.agileai.bpm.model.VariableType;
import com.agileai.bpm.model.WatchActivityType;
import com.agileai.util.StringUtil;

public class ProcessFactory {
	
	public ProcessDefineDocument createProcessDefineDocument(Process process){
		ProcessDefineDocument pdd = null;
		String defineXML = process.getDefineXML();
		if (StringUtil.isNullOrEmpty(defineXML)){
			pdd = ProcessDefineDocument.Factory.newInstance();
			ProcessDefine processDefine = pdd.addNewProcessDefine();
			processDefine.setName(process.getName());
			processDefine.setCode(process.getCode());
			processDefine.setDescription(process.getDesc());
			processDefine.setVersion(process.getVersion());
		}
		else{
			try {
				pdd = ProcessDefineDocument.Factory.parse(defineXML);
				pdd.getProcessDefine().setDescription(process.getDesc());
				pdd.getProcessDefine().setName(process.getName());
			} catch (XmlException e) {
				e.printStackTrace();
			}
		}
		pdd.getProcessDefine().setId(process.getId());
		return pdd;
	}
	
	public ProcessDefineDocument createProcessDefineDocument(String defineXML){
		ProcessDefineDocument pdd = null;
		try {
			pdd = ProcessDefineDocument.Factory.parse(defineXML);
		} catch (XmlException e) {
			e.printStackTrace();
		}
		return pdd;
	}
	
	private void packProcess(Process process,ProcessDefineDocument processDefineDocument){
		ProcessDefine processDefine = processDefineDocument.getProcessDefine();
		String defineXML = processDefineDocument.toString();
		process.setCode(processDefine.getCode());
		process.setName(processDefine.getName());
		process.setDesc(processDefine.getDescription());
		process.setDefineXML(defineXML);
		process.setVersion(processDefine.getVersion());
		
		DataFields dataFields = processDefine.getDataFields();
		if (dataFields == null)
			dataFields = processDefine.addNewDataFields();
		VariableType[] pVariableTypes = dataFields.getDataFieldArray();
		
		for (int i=0;i < pVariableTypes.length;i++){
			VariableType variableType = pVariableTypes[i];
			ProcessVariable processVariable = new ProcessVariable();
			processVariable.setCode(variableType.getCode());
			processVariable.setDesc(variableType.getDescription());
			processVariable.setVarType(variableType.getDataType().toString());
			processVariable.setInitialValue(variableType.getInitialValue());
			process.getVariableList().add(processVariable);
		}
		
		Activities activities = processDefine.getActivities();
		StartActivityType startActivityType = activities.getStartActivity();
		
		Activity startActivity = new Activity();
		startActivity.setId(startActivityType.getId());
		startActivity.setActType(Activity.ActTypes.start);
		startActivity.setCode(startActivityType.getCode());
		startActivity.setName(startActivityType.getName());
		startActivity.setDesc(startActivityType.getDescription());
		
		process.setStartActivity(startActivity);
		process.getActivityList().add(startActivity);
		process.storeActivity(startActivity);
		
		ManualActivityType[] manualActivityTypes = activities.getManualActivityArray();
		if (manualActivityTypes != null){
			for (int i=0;i < manualActivityTypes.length;i++){
				ManualActivityType manualActivityType = manualActivityTypes[i];
				Activity activity = new Activity();
				activity.setActType(Activity.ActTypes.manual);
				activity.setId(manualActivityType.getId());
				activity.setCode(manualActivityType.getCode());
				activity.setName(manualActivityType.getName());
				activity.setDesc(manualActivityType.getDescription());
				activity.setBusinessURL(manualActivityType.getBusinessURL());
				activity.setMobileBizURL(manualActivityType.getMobileBizURL());

				process.getActivityList().add(activity);
				process.storeActivity(activity);
				
				InInterceptors inInterceptors = manualActivityType.getInInterceptors();
				OutInterceptors outInterceptors = manualActivityType.getOutInterceptors();
				
				if (inInterceptors != null)
					processInIntercepterAttributes(activity,inInterceptors);
				if (outInterceptors != null)
					processOutIntercepterAttributes(activity, outInterceptors);
			}
		}
		
		AuditActivityType[] auditActivityTypes = activities.getAuditActivityArray();
		if (auditActivityTypes != null){
			for (int i=0;i < auditActivityTypes.length;i++){
				AuditActivityType auditActivityType = auditActivityTypes[i];
				Activity activity = new Activity();
				activity.setActType(Activity.ActTypes.audit);
				activity.setId(auditActivityType.getId());
				activity.setCode(auditActivityType.getCode());
				activity.setName(auditActivityType.getName());
				activity.setDesc(auditActivityType.getDescription());
				activity.setBusinessURL(auditActivityType.getBusinessURL());
				activity.setMobileBizURL(auditActivityType.getMobileBizURL());

				process.getActivityList().add(activity);
				process.storeActivity(activity);
				
				InInterceptors inInterceptors = auditActivityType.getInInterceptors();
				OutInterceptors outInterceptors = auditActivityType.getOutInterceptors();
				
				if (inInterceptors != null)
					processInIntercepterAttributes(activity,inInterceptors);
				if (outInterceptors != null)
					processOutIntercepterAttributes(activity, outInterceptors);
			}
		}
		
		ForkActivityType[] forkActivityTypes = activities.getForkActivityArray();
		if (forkActivityTypes != null){
			for (int i=0;i < forkActivityTypes.length;i++){
				ForkActivityType forkActivityType = forkActivityTypes[i];
				Activity activity = new Activity();
				activity.setActType(Activity.ActTypes.fork);
				activity.setId(forkActivityType.getId());
				activity.setCode(forkActivityType.getCode());
				activity.setName(forkActivityType.getName());
				activity.setDesc(forkActivityType.getDescription());
				activity.setControlType(forkActivityType.getControlType().toString());

				process.getActivityList().add(activity);
				process.storeActivity(activity);
				
				InInterceptors inInterceptors = forkActivityType.getInInterceptors();
				OutInterceptors outInterceptors = forkActivityType.getOutInterceptors();
				
				if (inInterceptors != null)
					processInIntercepterAttributes(activity,inInterceptors);
				if (outInterceptors != null)
					processOutIntercepterAttributes(activity, outInterceptors);
			}
		}
		
		JoinActivityType[] joinActivityTypes = activities.getJoinActivityArray();
		if (joinActivityTypes != null){
			for (int i=0;i < joinActivityTypes.length;i++){
				JoinActivityType joinActivityType = joinActivityTypes[i];
				Activity activity = new Activity();
				activity.setActType(Activity.ActTypes.join);
				activity.setId(joinActivityType.getId());
				activity.setCode(joinActivityType.getCode());
				activity.setName(joinActivityType.getName());
				activity.setDesc(joinActivityType.getDescription());
				activity.setControlType(joinActivityType.getControlType().toString());
				activity.setMatchedFork(joinActivityType.getMatchedFork());

				process.getActivityList().add(activity);
				process.storeActivity(activity);
				
				InInterceptors inInterceptors = joinActivityType.getInInterceptors();
				OutInterceptors outInterceptors = joinActivityType.getOutInterceptors();
				
				if (inInterceptors != null)
					processInIntercepterAttributes(activity,inInterceptors);
				if (outInterceptors != null)
					processOutIntercepterAttributes(activity, outInterceptors);
			}
		}		
		
		WatchActivityType[] watchActivityTypes = activities.getWatchActivityArray();
		if (watchActivityTypes != null){
			for (int i=0;i < watchActivityTypes.length;i++){
				WatchActivityType watchActivityType = watchActivityTypes[i];
				Activity activity = new Activity();
				activity.setActType(Activity.ActTypes.watch);
				activity.setId(watchActivityType.getId());
				activity.setCode(watchActivityType.getCode());
				activity.setName(watchActivityType.getName());
				activity.setDesc(watchActivityType.getDescription());

				process.getActivityList().add(activity);
				process.storeActivity(activity);
				
				InInterceptors inInterceptors = watchActivityType.getInInterceptors();
				OutInterceptors outInterceptors = watchActivityType.getOutInterceptors();
				
				if (inInterceptors != null)
					processInIntercepterAttributes(activity,inInterceptors);
				if (outInterceptors != null)
					processOutIntercepterAttributes(activity, outInterceptors);
			}
		}	
		
		InvokeActivityType[] invokeActivityTypes = activities.getInvokeActivityArray();
		if (invokeActivityTypes != null){
			for (int i=0;i < invokeActivityTypes.length;i++){
				InvokeActivityType invokeActivityType = invokeActivityTypes[i];
				Activity activity = new Activity();
				activity.setActType(Activity.ActTypes.invoke);
				activity.setId(invokeActivityType.getId());
				activity.setCode(invokeActivityType.getCode());
				activity.setName(invokeActivityType.getName());
				activity.setDesc(invokeActivityType.getDescription());

				process.getActivityList().add(activity);
				process.storeActivity(activity);
				
				InInterceptors inInterceptors = invokeActivityType.getInInterceptors();
				OutInterceptors outInterceptors = invokeActivityType.getOutInterceptors();
				
				if (inInterceptors != null)
					processInIntercepterAttributes(activity,inInterceptors);
				if (outInterceptors != null)
					processOutIntercepterAttributes(activity, outInterceptors);
			}
		}	
		
		EndActivityType endActivityType = activities.getEndActivity();
		Activity endActivity = new Activity();
		endActivity.setActType(Activity.ActTypes.end);
		endActivity.setId(endActivityType.getId());
		endActivity.setCode(endActivityType.getCode());
		endActivity.setName(endActivityType.getName());
		endActivity.setDesc(endActivityType.getDescription());
		
		process.getActivityList().add(endActivity);
		process.storeActivity(endActivity);
		
		TransitionType[] transitionTypes = processDefine.getTransitions().getTransitionArray();
		if (transitionTypes != null){
			for (int i=0;i < transitionTypes.length;i++){
				TransitionType transitionType = transitionTypes[i];
				
				Transition transition = new Transition();
				transition.setId(transitionType.getId());
				String fromId = transitionType.getFrom();
				String fromCode = ProcessDefineUtil.getActivityCode(processDefine, fromId);
				Activity fromActivity = process.getActivityContainer().get(fromCode);
				transition.setFromActivity(fromActivity);
				
				String toActId = transitionType.getTo();
				String toActCode = ProcessDefineUtil.getActivityCode(processDefine, toActId);
				Activity toActivity = process.getActivityContainer().get(toActCode);
				if (toActivity != null){
					transition.setToActivity(toActivity);					
				}

				transition.setCode(transitionType.getCode());
				if (transitionType.getType() != null){
					String transType = transitionType.getType().toString();
					transition.setTransType(transType);
				}

				transition.setName(transitionType.getName());
				transition.setDesc(transitionType.getDescription());
				transition.setExpression(transitionType.getExpression());
				
				process.getTransitionList().add(transition);
			}
		}
	}
	
	public Process createProcess(InputStream inputStream){
		Process process = new Process();
		try {
			ProcessDefineDocument processDefineDocument = ProcessDefineDocument.Factory.parse(inputStream);
			this.packProcess(process, processDefineDocument);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (XmlException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return process;
	}
	
	
	public Process createProcess(String defineXML){
		Process process = new Process();
		try {
			ProcessDefineDocument processDefineDocument = ProcessDefineDocument.Factory.parse(defineXML);
			this.packProcess(process, processDefineDocument);
		} catch (XmlException e) {
			e.printStackTrace();
		}
		return process;
	}
	
	public Process createProcess(File processXmlFile) {
		Process process = new Process();
		try {
			InputStream inputStream = new FileInputStream(processXmlFile);
			process = createProcess(inputStream);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return process;
	}
	
	private void processInIntercepterAttributes(Activity activity,InInterceptors inInterceptors){
		if (inInterceptors != null){
			InterceptorModel[] interceptors = inInterceptors.getInterceptorModelArray();
			List<BaseInterceptor> interceptorList = activity.getInIntercepterList();
			InterceptorFactory interceptorFactory = new InterceptorFactory();
			for (int i=0;i < interceptors.length;i++){
				InterceptorModel model = interceptors[i];
				BaseInterceptor interceptor = interceptorFactory.create(model,activity);
				interceptor.setPosition(com.agileai.bpm.interceptor.BaseInterceptor.Position.in);
				interceptorList.add(interceptor);
			}
		}
	}
	
	private void processOutIntercepterAttributes(Activity activity,OutInterceptors outInterceptors){
		if (outInterceptors != null){
			InterceptorModel[] interceptors = outInterceptors.getInterceptorModelArray();
			List<BaseInterceptor> interceptorList = activity.getOutIntercepterList();
			InterceptorFactory interceptorFactory = new InterceptorFactory();
			for (int i=0;i < interceptors.length;i++){
				InterceptorModel model = interceptors[i];
				BaseInterceptor interceptor = interceptorFactory.create(model,activity);
				interceptor.setPosition(com.agileai.bpm.interceptor.BaseInterceptor.Position.out);
				interceptorList.add(interceptor);
			}
		}	
	}
}
